import type { DefaultBodyType, JsonBodyType, StrictRequest } from "msw";
import { HttpResponse, delay, passthrough } from "msw";

type ResponseResolverInfo<
  ResolverExtraInfo extends Record<string, unknown>,
  RequestBodyType extends DefaultBodyType = DefaultBodyType,
> = {
  request: StrictRequest<RequestBodyType>;
  requestId: string;
} & ResolverExtraInfo;

/**
 * 通用分页查询
 */
export interface PaginationQuery {
  currentPage?: number;
  pageSize?: number;
  keyword?: string;
}

export interface ResponseDTO<Data = unknown> {
  data?: Data;
  errCode?: string;
  errMsg?: string;
  success?: boolean;
}

export interface PaginationDTO<Entity> {
  currentPage: number;
  hasMore: boolean;
  isDownload: boolean;
  list: Entity[];
  pageSize: number;
  pages: number;
  total: number;
}

/* 全局透传 */
export const GlobalPassthrough = false;

export const success = <T>(data: T) => {
  return {
    data,
    //errCode: "",
    //success: true,
  };
};

export const paginationDTO = <Entity>(
  list: Entity[],
  total: number,
  pageSize: number,
  currentPage: number,
) => {
  const pages = Math.ceil(total / pageSize);
  let hasMore = currentPage < pages;
  return success({
    currentPage,
    pageSize: pageSize,
    isDownload: false,
    hasMore,
    list,
    pages,
    total,
  });
};

export type PaginationEntityBuildParam = {
  base: number;
  pageSize: number;
  index: number;
  count: number;
  pages: number;
  total: number;
};

export type BuilderUtil<
  UtilData,
  Query extends DefaultBodyType,
  Entity,
  Params extends Record<string, unknown> = Record<string, unknown>,
> = (
  utilData: UtilData,
  info: ResponseResolverInfo<Params, Query>,
  query: Query,
) => Entity | Promise<Entity>;

export const withPagination =
  <
    Entity,
    Query extends PaginationQuery,
    Params extends Record<string, unknown> = Record<string, unknown>,
  >(
    builder: BuilderUtil<PaginationEntityBuildParam, Query, Entity, Params>,
    pass: boolean = false,
    total = 231,
    sort = (_: Entity, __: Entity) => 1,
  ) =>
  async (info: ResponseResolverInfo<Params, Query>) => {
    const query = await info.request.json();
    if (pass || GlobalPassthrough) {
      return passthrough();
    }
    const TOTAL = total;
    let base: number = (query.currentPage || 1) - 1;
    let pageSize = query.pageSize || 10;
    const pages = Math.ceil(TOTAL / pageSize);
    let hasMore = base + 1 < pages;
    if (base + 1 > pages) {
      base = pages - 1;
    }
    const count = total === 0 ? 0 : base + 1 === pages ? TOTAL - base * pageSize : pageSize;
    const listBuilder: (Entity | Promise<Entity>)[] = Array(count)
      .fill(0)
      .map((_, index) =>
        builder({ base, pageSize, index, count, pages, total: TOTAL }, info, query),
      );
    const list = await Promise.all(listBuilder);
    list.sort(sort);
    return HttpResponse.json<ResponseDTO<PaginationDTO<Entity>>>({
      data: {
        currentPage: base + 1,
        pageSize: pageSize,
        isDownload: false,
        hasMore,
        list,
        pages,
        total: TOTAL,
      },
      errCode: "",
      success: true,
    });
  };

export const withResponseSuccess =
  <
    ReturnType,
    Query extends DefaultBodyType = Record<string, unknown>,
    Params extends Record<string, unknown> = Record<string, unknown>,
  >(
    builder: BuilderUtil<unknown, Query, ReturnType, Params>,
    pass = false,
    duration = 500,
  ) =>
  async (info: ResponseResolverInfo<Params, Query>) => {
    if (pass || GlobalPassthrough) {
      return passthrough();
    }
    let query: Query = {} as Query;
    try {
      query = await info.request?.json();
    } catch (_error) {
      // console.error(error);
    }
    const data = await builder(void 0, info, query);
    if (data !== undefined) {
      if (duration) {
        await delay(duration);
      }
      return HttpResponse.json<ResponseDTO<ReturnType>>(success(data));
    }
  };

export const withResponseFailure =
  <
    ReturnType,
    Query extends DefaultBodyType,
    Params extends Record<string, unknown> = Record<string, unknown>,
  >(
    builder: BuilderUtil<unknown, Query, ReturnType, Params>,
    pass = false,
    duration = 500,
  ) =>
  async (info: ResponseResolverInfo<Params, Query>) => {
    if (pass || GlobalPassthrough) {
      return passthrough();
    }
    const query = await info.request?.json();
    const data = await builder(void 0, info, query);
    if (duration) {
      await delay(duration);
    }
    return HttpResponse.json<ResponseDTO<ReturnType>>({
      data,
      errCode: "1000001",
      success: false,
    });
  };

export const withResponseJson =
  <
    ReturnType extends JsonBodyType,
    Query extends DefaultBodyType,
    Params extends Record<string, unknown> = Record<string, unknown>,
  >(
    builder: BuilderUtil<unknown, Query, ReturnType>,
    pass = false,
    duration = 500,
  ) =>
  async (info: ResponseResolverInfo<Params, Query>) => {
    if (pass || GlobalPassthrough) {
      return passthrough();
    }
    const query = await info.request?.json();
    const data = await builder(void 0, info, query);
    if (data !== undefined) {
      if (duration) {
        await delay(duration);
      }
      return HttpResponse.json<ReturnType>(data);
    }
  };

export const encryptString = (str: string) => {
  return `${str.substring(0, 3)} **** **** ${str.substring(str.length - 3)}`;
};
